#include "stdafx.h"
#include "xKernel/IxReceiveMessage.h"
#include "Util.h"
#include "MsgDispatcher.h"

CxMsgDispatcher::CxMsgDispatcher()
{}

CxMsgDispatcher::~CxMsgDispatcher()
{}

HRESULT CxMsgDispatcher::Initialize(IxView* pRootView)
{
    m_spRootView = pRootView;
    ATLASSERT(m_spRootView);
    return S_OK;
}

HRESULT CxMsgDispatcher::Uninitialize()
{
    m_spRootView = NULL;
    return S_OK;
}

HRESULT CxMsgDispatcher::DispatchMessage(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* lpRet, LPBOOL pbHandled)
{
    if (!lpRet && !pbHandled)
    {
        return E_INVALIDARG;
    }

    switch (message)
    {
    case WM_MOUSEMOVE:
        *lpRet = OnMouseMove(wParam, lParam, pbHandled);
        break;
    default:
        break;
    }

    return S_OK;
}

LRESULT CxMsgDispatcher::OnMouseMove(WPARAM wParam, LPARAM lParam, LPBOOL pbHandled)
{
    POINT pt = {0};
    pt.x = GET_X_LPARAM(lParam); 
    pt.y = GET_Y_LPARAM(lParam); 

    VIEWS views;
    ::xKernel::GetViewsByPoint(m_spRootView, pt, views);

    VIEWS::iterator it1 = views.begin();
    VIEWS::iterator it2 = m_vecViews.begin();

    while (it1 != views.end() && it2 != m_vecViews.end())
    {
        if (*it1 == *it2)
        {
            ++it1;
            ++it2;
            continue;
        }
        break;
    }

    // mouse leave
    if (!m_vecViews.empty() && it2 != m_vecViews.end())
    {
        EVENTPARAM param;
        param.message = XM_MOUSELEAVE;
        param.wParam = wParam;
        param.lParam = lParam;
        param.bHandled = FALSE;

        BOOL bEventHandled = FALSE;

        VIEWS::iterator it = m_vecViews.end() - 1;
        while (it != it2 && !bEventHandled)
        {
            CComQIPtr<IxReceiveMessage> spRecv = *it;
            if (spRecv)
            {
                spRecv->OnMessage(&param, &bEventHandled);
            }
            --it;
        }

        if (!bEventHandled)
        {
            CComQIPtr<IxReceiveMessage> spRecv = *it2;
            if (spRecv)
            {
                spRecv->OnMessage(&param, &bEventHandled);
            }
        }
    }

    // mouse enter
    if (!views.empty() && it1 != views.end())
    {
        EVENTPARAM param;
        param.message = XM_MOUSEENTER;
        param.wParam = wParam;
        param.lParam = lParam;
        param.bHandled = FALSE;

        BOOL bEventHandled = FALSE;

        VIEWS::iterator it = views.end() - 1;
        while (it != it1 && !bEventHandled)
        {
            CComQIPtr<IxReceiveMessage> spRecv = *it;
            if (spRecv)
            {
                spRecv->OnMessage(&param, &bEventHandled);
            }
            --it;
        }

        if (!bEventHandled)
        {
            CComQIPtr<IxReceiveMessage> spRecv = *it1;
            if (spRecv)
            {
                spRecv->OnMessage(&param, &bEventHandled);
            }
        }
    }

    // mouse move
    {
        EVENTPARAM param;
        param.message = XM_MOUSEMOVE;
        param.wParam = wParam;
        param.lParam = lParam;
        param.bHandled = FALSE;

        BOOL bEventHandled = FALSE;

        VIEWS::reverse_iterator rit = views.rbegin();
        while (rit != views.rend() && !bEventHandled)
        {
            CComQIPtr<IxReceiveMessage> spRecv = *rit;
            if (spRecv)
            {
                spRecv->OnMessage(&param, &bEventHandled);
            }
            ++rit;
        }
    }

    return 0;
}